
                /*********************************************
                **                                          **
                **                                          **
                **                  cs.3.C                  **
                **                                          **
                **                                          **
                *********************************************/
                /*********************************************
                **                                          **
                **         Author Jean-Marc Adamo           **
                **       Copyright (C) 1997-2008 JMA        **
                *********************************************/

/*
** testsyncSR3.C
** testing Sdf::alt with composite chan utilization:
** ChanR and ChanRD<T>
** Needs at least 3 processes
*/

#include "arch.h"

//user program
Global_id gid1;
Global_id gid2;
Global_id gid3;
Coll_id cid;

void init_gid(int, char **){
   gid1.set();
   gid2.set();
   gid3.set();
   cid.set();
   fprintf(Sdf::trace, "node%d: gid1.tag=%d, gid2.tag=%d, gid3.tag=%d, cid.tag=%d\n",
           Sdf::PROC_ID, gid1.get(), gid2.get(), gid3.get(), cid.get());
   fflush(Sdf::trace);
}

ChanRD<int> *chan;
ChanRD<int> *chan2_0;
ChanR *chan2_1;


class Sender: public S_Thread{

   public:

        Sender()
                : S_Thread((Smf0_ptr)&Sender::body){}


        void body(){

           fprintf(Sdf::trace, "node %d, in proc %d before for loop\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           int msg;

           for(int j=0; j<2; j++){

              msg = j+Sdf::PROC_ID;
              chan->send(msg);

             fprintf(Sdf::trace, "node %d, in proc %d after send chan, j = %d\n",
                     Sdf::PROC_ID, 0, j);
             fflush(Sdf::trace);
           }

           msg = 50+Sdf::PROC_ID;
           chan2_0->send(msg);

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_0.0\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           chan2_1->send();

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_1.0\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           msg = 100+Sdf::PROC_ID;
           chan2_0->send(msg);

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_0.1\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           chan2_1->send();

           fprintf(Sdf::trace, "node %d, in proc %d after send chan2_1.1\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);

           fprintf(Sdf::trace, "node %d, in proc %d sender ends up\n",
                   Sdf::PROC_ID, 0);
           fflush(Sdf::trace);
    }
};


class Receiver: public S_Thread{

   public:

        int msg;

        Receiver()
                : S_Thread((Smf0_ptr)&Receiver::body){}

        void body(){

         fprintf(Sdf::trace, "node %d, in proc %d before for loop\n",
                 Sdf::PROC_ID, 1);
         fflush(Sdf::trace);

         for(int j=0; j<2; j++){

           chan->recv(msg);

           fprintf(Sdf::trace, "node %d, in proc %d after recv chan, j = %d, msg = %d\n",Sdf::PROC_ID, 1, j, msg);
           fflush(Sdf::trace);
         }

         chan2_0->recv(msg);

         fprintf(Sdf::trace, "node %d, in proc %d after recv chan2_0, msg = %d\n", Sdf::PROC_ID, 1, msg);
         fflush(Sdf::trace);

         chan2_1->recv();

         fprintf(Sdf::trace, "node %d, in proc %d after recv chan2_1\n", Sdf::PROC_ID, 1);
         fflush(Sdf::trace);

         Alts *alt_table[2];
         alt_table[0] =  new AltRDrecv<int>(chan2_0, 
                                            this,
                                            (Smf2_ptr)&Receiver::alt_body,
                                            0,
                                            msg);

         alt_table[1] =  new AltR(chan2_1, 
                                  this,
                                  (Smf2_ptr)&Receiver::alt_body,
                                  0);

         AltCtrl *alt_ctrl = new AltCtrl(2, alt_table);
         for(int i = 0; i< 2; i++){
              Sdf::alt(alt_ctrl);
         }

         delete alt_table[0], delete alt_table[1];
         delete alt_ctrl;

         fprintf(Sdf::trace, "node %d, in proc %d receiver ends up\n",
                 Sdf::PROC_ID, 1);
         fflush(Sdf::trace);

       }

       void alt_body(int rank, void *arg_ptr){

            fprintf(Sdf::trace,"node %d, in proc %d in alt_body, rank = %d\n",
                           Sdf::PROC_ID, 1, rank);

            if(rank == 1)
             fprintf(Sdf::trace, "node %d, in proc %d in alt_body.%d\n",
                     Sdf::PROC_ID, 1, rank);
            else
             fprintf(Sdf::trace, "node %d, in proc %d in alt_body.%d, msg = %d\n",
                           Sdf::PROC_ID, 1, rank, msg);
            fflush(Sdf::trace);

       }
};

class Root_proc: public Thread{

   public:
        Root_proc()
                : Thread((Tmf0_ptr)&Root_proc::body){}

        void body(){

            fprintf(Sdf::trace, "node %d, in Root_proc::body1\n", Sdf::PROC_ID);
            fflush(Sdf::trace);

        chan = new ChanRD<int>(gid1, (Sdf::PROC_ID+1)%Sdf::PROC_NB);

        chan2_0 = new ChanRD<int>(gid2, (Sdf::PROC_ID+1)%Sdf::PROC_NB);
        chan2_1 = new ChanR(gid3, (Sdf::PROC_ID+2)%Sdf::PROC_NB);

        Sdf::barrier(cid);
                //synchronizes chan construction(no longer
                //necessary starting from version 5)

        Sender * sender = new Sender;
        Receiver * receiver = new Receiver;

        /*####*/
        fprintf(Sdf::trace, "node %d, chan = %d, chan2[0] = %d, chan2[1] = %d, sender = %d, receiver = %d\n",
        Sdf::PROC_ID, chan, chan2_0, chan2_1, sender, receiver);

        fprintf(Sdf::trace, "node %d, in Root_proc::body2\n", Sdf::PROC_ID);
        fflush(Sdf::trace);

        S_Thread *proc_tabl[2] = {sender, receiver};
        int pri[2] = {1, 1};
        par(2, proc_tabl, pri);

        fprintf(Sdf::trace, "node %d, in Root_proc::body3\n", Sdf::PROC_ID);
        fflush(Sdf::trace);

        Sdf::barrier(cid);
                     //synchronizes chan destruction
        delete chan2_0;
        delete chan2_1;
        delete chan;
        delete sender;
        delete receiver;
    }
};

//end of user program


MAIN(Root_proc, init_gid, Sdf::empty, Sdf::empty)


